import { Definition } from "../entities/types";
import * as vscode from "vscode";
import { TreeSitter } from "../../../../core/treesitter/TreeSitter";
import { DefinitionInfo, FunctionInfo } from "../entities/types";
import { cleanTypeName, escapeRegExp, isBasicType } from "../utils/utils";
import { Logger } from "../../../../src/logger/Logger";

export class ParametersDefinitionsProcessor {
  public static async extract(document: vscode.TextDocument, funcInfo: FunctionInfo, functionRange: vscode.Range): Promise<Definition[]> {
    // 过滤掉基本类型并去重参数类型名称
    const uniqueParamTypes = Array.from(new Set(funcInfo.paramTypeName?.filter((paramType) => !isBasicType(paramType)) || []));

    // 并行获取所有参数类型的定义
    const paramDefinitionPromises = uniqueParamTypes.map(async (paramType) => {
      try {
        // 去除可能的模板和引用等修饰
        const cleanParamType = cleanTypeName(paramType);

        // 查找类型定义
        const typeDefinition = await this.getFullDefinitionByName(document, cleanParamType, functionRange);

        return typeDefinition;
      } catch (error) {
        Logger.error(`Error resolving parameter type ${paramType}: ${error}`);
        return undefined;
      }
    });

    // 等待所有参数类型定义解析完成
    const resolvedDefinitions = await Promise.all(paramDefinitionPromises);

    // 过滤掉 undefined 值
    return resolvedDefinitions.filter((def): def is DefinitionInfo => def !== undefined).map((def: DefinitionInfo) => this.getDefinition(def));
  }

  public static getDefinition(info: DefinitionInfo): Definition {
    const sourceCode = info.document.getText(info.range);
    const definition: Definition = {
      type: info.type,
      name: info.name,
      definition: sourceCode,
    };
    return definition;
  }

  /**
   * 快捷方法：根据名称获取完整代码块
   * @param document 文档
   * @param name 名称
   * @param functionRange 指定的范围
   * @returns Promise<DefinitionInfo | undefined>
   */
  public static async getFullDefinitionByName(document: vscode.TextDocument, typeName: string, functionRange: vscode.Range): Promise<DefinitionInfo | undefined> {
    try {
      if (isBasicType(typeName)) {
        return undefined;
      }
      // 查找定义位置
      const definitionLocation = await this.findDefinitionPositionByName(document, typeName, functionRange);

      if (!definitionLocation) {
        Logger.info(`${typeName} not found`);
        return undefined;
      }

      // 获取完整代码
      return await this.getCodeAtLocation(definitionLocation, typeName);
    } catch (error) {
      Logger.error(`Error getting definition for ${typeName}: ${error}`);
      return undefined;
    }
  }

  /**
   * 根据名称查找定义位置的通用方法
   * @param document 当前文档
   * @param name 要查找的名称（类名、返回值类型等）
   * @param functionRange 可选的搜索范围，优先在此范围内匹配
   * @returns Promise<vscode.Location | null>
   */
  public static async findDefinitionPositionByName(document: vscode.TextDocument, name: string, functionRange?: vscode.Range): Promise<vscode.Location | null> {
    const text = document.getText();

    // 创建正则表达式，确保name前后不是字母、数字、下划线
    // 并排除注释行
    const nameRegex = new RegExp(`(?<![\\w])${escapeRegExp(name)}(?![\\w])`, "g");

    // 如果提供了functionRange，先在指定范围内搜索
    if (functionRange) {
      const rangeText = document.getText(functionRange);
      const rangeRegex = new RegExp(`(?<![\\w])${escapeRegExp(name)}(?![\\w])`, "g");

      let match: RegExpExecArray | null;
      while ((match = rangeRegex.exec(rangeText)) !== null) {
        const matchIndex = functionRange.start.character + match.index;
        const position = document.positionAt(document.offsetAt(functionRange.start) + match.index);

        // 获取匹配所在的行
        const line = document.lineAt(position);

        // 检查是否为注释行
        const trimmedLine = line.text.trim();
        if (!trimmedLine.startsWith("//") && !trimmedLine.startsWith("*")) {
          let ans = await this.resolveDefinition(document, position);
          return ans ? ans[0] : null;
        }
      }
    }

    // 如果在functionRange中未找到，则在全文中搜索
    let match: RegExpExecArray | null;
    while ((match = nameRegex.exec(text)) !== null) {
      const matchIndex = match.index;
      const position = document.positionAt(matchIndex);

      // 获取匹配所在的行
      const line = document.lineAt(position);

      // 检查是否为注释行
      const trimmedLine = line.text.trim();
      if (!trimmedLine.startsWith("//") && !trimmedLine.startsWith("*")) {
        let ans = await this.resolveDefinition(document, position);
        return ans ? ans[0] : null;
      }
    }

    return null;
  }

  /**
   * 根据名称获取对应代码文本（会先尝试从缓存中查找范围）
   * @param location VSCode 位置信息
   * @param name 要查找的名称（类名、结构体名、枚举名等）
   * @returns Promise<DefinitionInfo | undefined>
   */
  public static async getCodeAtLocation(location: vscode.Location, name: string): Promise<DefinitionInfo | undefined> {
    try {
      const document = await vscode.workspace.openTextDocument(location.uri);
      const uriStr = location.uri.toString();
      let uriMap = TreeSitter.getInstance().getCacheMapByUriStr(uriStr);
      if (!uriMap) {
        await TreeSitter.getInstance().cacheCodeRanges(location);
        uriMap = TreeSitter.getInstance().getCacheMapByUriStr(uriStr);
      }
      if (uriMap && uriMap.has(name)) {
        const cached = TreeSitter.getInstance().getCachedDefinition(document, name);
        return cached;
      }
      return undefined;
    } catch (error) {
      Logger.error(`Error retrieving code at location: ${error}`);
      return undefined;
    }
  }

  /**
   * 解析定义的内部方法（可以根据需要缓存）
   * @param document 文档
   * @param position 位置
   * @returns Promise<vscode.Location[] | null>
   */
  public static async resolveDefinition(document: vscode.TextDocument, position: vscode.Position): Promise<Array<vscode.Location> | null> {
    try {
      const editor = vscode.window.activeTextEditor;
      if (editor && editor.selection.contains(position)) {
        // 如果当前位置在选中区域内，尝试取消选中
        editor.selection = new vscode.Selection(position, position);
      }
      let definitions = await vscode.commands.executeCommand<vscode.Location[]>("vscode.executeDefinitionProvider", document.uri, position);
      definitions = this.filterStandardLibrary(definitions);
      if (definitions && definitions.length === 1) {
        return [definitions[0]];
      }
      let bestMatch: any = [];
      if (definitions && definitions.length > 1) {
        definitions.forEach((item: vscode.Location) => {
          if (item.uri === document.uri) {
            bestMatch.push(item);
          }
        });
        return bestMatch.length ? bestMatch : definitions;
      }
      return null;
    } catch (error) {
      Logger.error(`Definition resolution error: ${error}`);
      return null;
    }
  }

  private static filterStandardLibrary(definitions: vscode.Location[]): vscode.Location[] {
    return (
      definitions?.filter((item) => {
        return !this.isStandardLibrary(item.uri);
      }) || []
    );
  }

  private static isStandardLibrary(uri: vscode.Uri): boolean {
    const uriPath = uri.path;
    const projectPath = this.getCurrentProjectPath();
    if (!projectPath) {
      return false;
    }
    return !uriPath.startsWith(projectPath);
  }

  private static getCurrentProjectPath(): string | null {
    const workspaceFolders = vscode.workspace.workspaceFolders;
    return workspaceFolders && workspaceFolders.length > 0 ? workspaceFolders[0].uri.path : null;
  }
}
